/*
 * R2.c
 *
 *      Created on: Sep 20, 2013
 *              Authors: Joseph DeLong, Justin Hamric, Alex Newcomer, Alex Bouvy
 */

#include <string.h>
#include <dos.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include "mpx_supt.h"
#include "defines.h"
#include "mpx_pcb.h"

//R1 Command Prototypes
int commhand(struct MPX_Q *ready, struct MPX_Q *blocked); //added struct MPX_Q's to be passed to ALL functions as needed
void date(char* input_tok[6], int command_args);
int help(int argc, char *argv[6]);
int ls(char *input[6], int command_args);
int r_exit(int *exit);
void version(void);
void clear(void);

//R2 Procedure Prototypes
MPX_PCB *allocatePCB(void);
int freePCB(MPX_PCB *pcbName);
MPX_PCB *setupPCB(char processName[9], int processClass, int priority);
void insert_blocked(MPX_PCB* pcb, MPX_Q* blocked);
void insert_ready(MPX_PCB* pcb, MPX_Q* ready);
int removePCB(struct MPX_PCB* pcbJ, struct MPX_Q* q);
void show_all(struct MPX_Q *r, struct MPX_Q *b);
void disp(struct MPX_Q *r, struct MPX_Q *b);
void show_ready(struct MPX_Q *r);
void show_blocked(struct MPX_Q *b);
void show_pcb(struct MPX_PCB* pcb);
void blockPCB(char processName[9], struct MPX_Q *a, struct MPX_Q *b);
void unblockPCB(char processName[9], struct MPX_Q *a, struct MPX_Q *b);
MPX_PCB* find_ready(char processName[9], struct MPX_Q *r);
MPX_PCB* find_blocked(char processName[9], struct MPX_Q *b);

//suggested R2 commands
void R2Init(struct MPX_Q *ready, struct MPX_Q *blocked); //this will initialize our queues
void R2Clean(struct MPX_Q *ready, struct MPX_Q *blocked); //this will clear queues, reclaim all memory allocated to PCBs in them

/*
 * MAIN function
 * This is the meat and potatoes of the Appaloosa OS. Everything gets run through here.
 * parameters: NOTHING
 * returns: Integer representing normal operation/termination (0) or an error code (non-zero)
 */
int main(void) {
        struct MPX_Q *ready, *blocked;
        sys_init(MODULE_R2);
        logo(); //animated welcome screen
        clear(); //clear the screen before allowing user input
        /*
         * THIS SHOULD BE WHERE WE ALLOCATE MEMORY FOR SYSTEM STARTUP,
         * AMONG OTHER THINGS
         */
        R2Init(ready, blocked);
        commhand(ready, blocked);
        /*
         * THIS SHOULD BE WHERE WE DE-ALLOCATE ALL MEMORY BEFORE EXITING,
         * AMONG OTHER THINGS
         */
        R2Clean(ready, blocked);
        sys_exit();
        return 0; //THIS SHOULD ACTUALLY BE A DYNAMICALLY OBTAINED INTEGER AS ERROR CODES ARE/ARE NOT CAPTURED AND HANDLED
}
//---------------------------------------------------------R1 COMMANDS---------------------------------------------------------//
/*
 * COMMHAND
 * Written by Alex Bouvy
 * Command Handler for Appaloosa OS
 * parameters: NONE
 * returns: Integer representing normal termination (0), or an error code (non-zero)
 */
int commhand(struct MPX_Q *ready, struct MPX_Q *blocked) {
        MPX_PCB* newpcb;
        int found;
        char prompt[3] = "$$>";

        //------------comm literals----------------
        char c1[3]="ls\0";
        char c2[5]="date\0";
        char c3[5]="exit\0";
        char c4[5]="help\0";
        char c5[8]="version\0";
        char c6[11]="create-pcb\0";
        char c7[11]="delete-pcb\0";
        char c8[6]="block\0";           //
        char c9[8]="unblock\0";         //
        char c10[8]="suspend\0";        //
        char c11[7]="resume\0";         //
        char c12[13]="set-priority\0";
        char c13[9]="show-pcb\0";
        char c14[9]="show-all\0";
        char c15[11]="show-ready\0";
        char c16[13]="show-blocked\0";
        char d00[4]="mem\0";
        char d01[6]="qexit\0";
        char d02[6]="clear\0";
        char d03[7]="carrot\0";
	char d04[5]="disp\0";
        
        //------------/comm literals---------------

        char input[256];
        char* input_tok[6];
        /*
         * One reason I think we might be having random errors with token-ization of our input from the user
         * is that we never truly allocate ANY memory for the char pointer strings (input_tok[0 through 5]).
         * How can we be sure that anything is ever being put into those array slots correctly if we don't
         * know if their contents even exist in memory?
         *
         * Comment by Joe, on 9/21/2013
         */
        int bufferSize = 256;
        int promptLength = 3;
        int gallop = 1; //set this horse to moving!
        int stringSize; //COMPILER IS NOT CORRECT, THIS VARIABLE IS USED
        int command_args=0;
        int max_args = 6;
        int i; 
        int alphaFlag = 0;
		int whichQueue = 0;
				//loop until user enters the exit command
        while(gallop) { //while still kicking up dust
                                
                                alphaFlag = 0;
								whichQueue = 0;
                command_args=0;
                promptLength = 3;
                sys_req(2,1, prompt, &promptLength);
                stringSize = sys_req(1, 1, input, &bufferSize);

                input_tok[0] = strtok(input," ");
                if(!strcmp(input_tok[0],"\n")){
                        continue;
                }
                else{
                        for(i=1;i<max_args;i++){
                                input_tok[i]=strtok(NULL," ");
                                if(input_tok[i]==NULL) break;
                                else command_args = i;
                        }
                }

                //hacky fix 1 for tokenization
                if(command_args==0){
                        strxfrm(input_tok[0],input_tok[0], strlen(input_tok[0]));
                        strcat(input_tok[0],"\0");
                }
                
                //hacky fix 2 for tokenization issue
                if(!(strcmp(input_tok[command_args],"\n"))){
                        input_tok[command_args] = NULL;
                        command_args--;
                }

                //command handling
                if(!(strcmp(input_tok[0],d00))) {
                        printf("Core Left: %d\n",coreleft());
                }
                else if(!(strcmp(input_tok[0],d01))) {
                        gallop=0;
                }
		else if(!(strcmp(input_tok[0],d04))) {
                        disp(ready,blocked);
                }
                else if(!(strcmp(input_tok[0],c1))) {
                        ls(input_tok, command_args);
                }
                else if(!(strcmp(input_tok[0],c2))){
                        date(input_tok, command_args);
                }
                else if(!(strcmp(input_tok[0],c3))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c3);
                        }
                        else r_exit(&gallop);
                }
                else if(!(strcmp(input_tok[0],c4))) {
                        help(command_args, input_tok);
                }
                else if(!(strcmp(input_tok[0],c5))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c5);
                        }
                        else version();
                }
                //create-pcb
                else if(!(strcmp(input_tok[0],c6))) {
                        if(command_args!=3){
                                printf("Invalid number of arguments provided.\n");
                        }
                        else if(!(*input_tok[2]==49||*input_tok[2]==48)){
                                printf("Invalid process class value provided.\n");
                        }
                        else if(atoi(input_tok[3])>127||atoi(input_tok[3])<-128){
                                printf("Invalid priority value provided.\n");
                        }
			else if(find_ready(input_tok[1],ready) != NULL){
                                printf("PCB '%s' already exists\n",input_tok[1]);
                        }
			else if(find_blocked(input_tok[1],blocked) != NULL){
                                printf("PCB '%s' already exists\n",input_tok[1]);
                        }
                        else{
                                                        for(i=0; i<strlen(input_tok[3]); i++){
                                                                if(isalpha((input_tok[3])[i])){
                                                                        alphaFlag = 1;
                                                                }
                                                        }
                                                        if(!alphaFlag){
                                                                newpcb = setupPCB(input_tok[1],atoi(input_tok[2]),atoi(input_tok[3]));
                                                                insert_ready(newpcb, ready);
								printf("PCB '%s' created.\n",input_tok[1]);
                                                        } else {
                                                                printf("parameter 3 is invalid\n");
                                                        }
                        }
                                        
                                }
                //delete-pcb
                else if(!(strcmp(input_tok[0],c7))) {
                        input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish deleted must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1], ready);
                                if(newpcb != NULL){
                                        removePCB(newpcb, ready);
                                        freePCB(newpcb);
                                        printf("PCB '%s' deletion succcessful.\n",input_tok[1]);        
                                }
                                else{
                                        newpcb = find_blocked(input_tok[1], blocked);
                                        if(newpcb != NULL){
                                                removePCB(newpcb, blocked);                             
                                                printf("PCB '%s' deletion succcessful.\n",input_tok[1]);
                                        }
                                         else printf("PCB not found.\n");
                                }  
                        }
                }
                else if(!(strcmp(input_tok[0],c8))) {
                       // printf(c8);
                       //printf(" recognized\n");
                                        if(input_tok[1] != NULL){
                                                if(command_args == 1){
                                                        if(strlen(input_tok[1]) <= 9){
                                                        blockPCB(input_tok[1], ready, blocked);
                                                } else {
                                                        printf("pcb name is too long.\n");
                                                }
                                                        } else {
                                                        printf("Too many arguments.\n");
                                                }
                                        } else {
                                                printf("Invalid first argument.\n");
                                        }
                                           }
                else if(!(strcmp(input_tok[0],c9))) {
                                        if(input_tok[1] != NULL){
                                                if(command_args == 1){
                                                        if(strlen(input_tok[1]) <= 9){
                                                        unblockPCB(input_tok[1], ready, blocked);
                                                } else {
                                                        printf("pcb name is too long.\n");
                                                }
                                                        } else {
                                                        printf("Too many arguments.\n");
                                                }
                                        } else {
                                                printf("Invalid first argument.\n");
                                        }
                }
                //suspend
                else if(!(strcmp(input_tok[0],c10))) {
                       input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish to suspend must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1], ready);
                                if(newpcb == NULL) newpcb = find_blocked(input_tok[1], blocked);
                                if(newpcb != NULL){
                                        (*newpcb).isSuspended=1;
                                        printf("PCB '%s' suspended.\n",(*newpcb).processName);
                                } else printf("PCB not found.\n");
                        }
                }
                //resume
                else if(!(strcmp(input_tok[0],c11))) {
                        input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish to suspend must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1], ready);
                                if(newpcb == NULL) newpcb = find_blocked(input_tok[1], blocked);
                                if(newpcb != NULL){
                                        (*newpcb).isSuspended=0;
                                        printf("PCB '%s' resumed.\n",(*newpcb).processName);
                                } else printf("PCB not found.\n");
                        }
                }
                //set-priority
                else if(!(strcmp(input_tok[0],c12))) {
                        //input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=2){
                                printf("Invalid number of arguments provided.\n");
                        }
			else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB specified must be 8 characters or less.\n");
                        }
			else if(atoi(input_tok[2])>127||atoi(input_tok[2])<-128){
                                printf("Invalid priority specified.\n");
                        }
			else{
				for(i=0; i<strlen(input_tok[2]); i++){
                                	if(isalpha((input_tok[2])[i])){
                                        	alphaFlag = 1;
                                	}
                        	}
				if(!alphaFlag){
					newpcb = find_ready(input_tok[1], ready);
                               		if(newpcb == NULL){
									newpcb = find_blocked(input_tok[1], blocked);
									whichQueue = 1;
									}
                                	if(newpcb != NULL){
                                        	(*newpcb).priority=atoi(input_tok[2]);
											if(!whichQueue){
												removePCB(newpcb, ready);
												insert_ready(newpcb, ready);
											}
                                        	printf("PCB '%s' priority changed.\n",(*newpcb).processName);
                                	} else printf("PCB not found.\n");
				}else printf("Invalid priority specified.\n");
                                
                        }
                }// end 12
                //show-pcb
                else if(!(strcmp(input_tok[0],c13))) {
                        input_tok[1][strlen(input_tok[1])-1] = '\0';
                        if(command_args!=1){
                                printf("Invalid number of arguments provided.\n");
                        }else if(strlen(input_tok[1])>8){
                                printf("The name of the PCB you wish deleted must be 8 characters or less.\n");
                        }else{
                                newpcb = find_ready(input_tok[1], ready);
                                if(newpcb == NULL) newpcb = find_blocked(input_tok[1], blocked);
                                if(newpcb != NULL){
                                        printf("Name: %s\n",(*newpcb).processName);
                                        printf("Class: %d\n",(*newpcb).processClass);
                                        printf("State: %d\n",(*newpcb).pcb_state);
                                        printf("Suspended: %d\n",(*newpcb).isSuspended);
                                        printf("Prio: %d\n",(*newpcb).priority);
                                } else printf("PCB not found.\n");
                        }
                }
                //show-all
                else if(!(strcmp(input_tok[0],c14))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c14);
                        }
                        else {
                                show_all(ready,blocked);
                        }
                }
                //show-ready
                else if(!(strcmp(input_tok[0],c15))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c15);
                        }
                        else show_ready(ready);
                }
                //show-blocked
                else if(!(strcmp(input_tok[0],c16))) {
                        if(command_args>0){
                                printf("Command %s does not accept arguments.\n",c16);
                        }
                        else show_blocked(blocked);
                }
                else if(!(strcmp(input_tok[0],d02))) {//CLEAR SCREEN
                        clear();
                }
                else if(!(strcmp(input_tok[0],d03))) {//CHANGE PROMPT
                        printf(d03);
                        printf(" recognized\n");
                //      if(input_tok[1] != NULL && input_tok[2] != NULL) {
                //              if(!isalnum(input_tok[1])) { //IF FIRST PARAMETER IS A CHAR
                //                      if(!isalnum(input_tok[2])) { //IF SECOND PARAMETER IS AN INT
                //                              carrot(((char)input_tok[1][1]), ((int)input_tok[2]));
                //                      }
                //                      else {
                //                              printf("Parameter 2 must be an integer\n");
                //                      }
                //              }
                //              else {
                //                      printf("Parameter 1 must be a single character\n");
                //              }
                //      }
                //      else {
                //              printf("This command must have two arguments: a character and an integer\n");
                //      }
                }
                else printf("Command '%s' not recognized\n",input_tok[0]);
        }
        return 0;
}

/*      DATE function
 *      Written by: Alex Newcomer
 *              Command: date (-s yyyy mm dd)
 *                      If the command, date, is submitted to the terminal, the date is displayed.
 *                      If the command is submitted with the -s flag and an 8 digit number, if the date is valid, the system date will be set to the provided date
 *                                      If the date submitted is not valid, a message will be sent to the terminal saying so.
 *
 */
typedef struct date_record {
        int day;
        int month;
        int year;
} date_record;

void date(char* input_tok[6], int command_args){
        int i, j;
        int daysInFebruary;
        int foundACharacter = 0;
        date_record currentDate, newDate;
        if(command_args == 4){
                //error check
                if(abs((strncmp(input_tok[1], "-s", 2)))){
                        // user entered invalid first arg
                        printf("date -> First argument is an invalid switch.\n");
                } else if(!(strncmp(input_tok[1], "-s", 2))){
                        //Alex's 9/19/2013 fixing the digit detection issue
                        foundACharacter = 0;
                        for(j=2; j < 5; j++){
                                for(i=0; i < strlen(input_tok[j]); i++){
                                        if(isalpha(input_tok[j][i])){
                                                foundACharacter = 1;
                                        }
                                }
                        }
                        if(foundACharacter){
                                printf("date -> You must enter digits not characters.\n");
                        }
                        //end Alex 9/19/2013
                        else
                                //check for yyyy(2) mm(3) dd(4), valid, not leapyear.
                                if(atoi(input_tok[3]) > 12 || atoi(input_tok[3]) < 1){
                                        //month too big
                                        printf("date -> too many months\n");
                                } else {
                                        //months and years are OK, check valid days
                                        //if february
                                        if(atoi(input_tok[3]) == 2){
                                                int leap = 0;
                                                if(atoi(input_tok[2])%400 == 0){
                                                        leap = 1;
                                                } else if (atoi(input_tok[2])%100 == 0){
                                                        leap = 0;
                                                } else if(atoi(input_tok[2])%4 == 0){
                                                        leap = 1;
                                                } else {
                                                        leap = 0;
                                                }
                                                if(leap){
                                                        daysInFebruary = 29;
                                                } else {
                                                        daysInFebruary = 28;
                                                }
                                                if(atoi(input_tok[4]) <= daysInFebruary){
                                                        //call date
                                                        date(input_tok, command_args);
                                                } else {
                                                        //exit with error (leap year)
                                                        printf("date -> leap year violation\n");
                                                }
                                        } else {//not february
                                                switch(atoi(input_tok[3])){
                                                case 1: case 3: case 5: case 7: case 8: case 10: case 12:
                                                        if((atoi(input_tok[4]) <= 31) && ( strlen(input_tok[2]) < 6) ){
                                                                //set date
                                                                newDate.month = atoi(input_tok[4]);
                                                                newDate.year = atoi(input_tok[2]);
                                                                newDate.day = atoi(input_tok[3]);
                                                                sys_set_date(&newDate);
                                                        } else {
                                                                printf("date -> input error\n");
                                                        }
                                                        break;
                                                case 4: case 6: case 9: case 11:
                                                        if(( atoi(input_tok[4]) <= 30 ) && ( strlen(input_tok[2]) < 6)){
                                                                //set date
                                                                newDate.month = atoi(input_tok[4]);
                                                                newDate.year = atoi(input_tok[2]);
                                                                newDate.day = atoi(input_tok[3]);
                                                                sys_set_date(&newDate);

                                                        } else {
                                                                printf("date -> your days are invalid\n");
                                                        }
                                                        break;
                                                }
                                        }
                                }
                }
                //date(input_tok, command_args);
        } else if(command_args != 0){
                printf("date -> You have entered the wrong number of arguments\n");
        } else { //no args, display the date!
                sys_get_date(&currentDate);
                printf("%d, %d, %d\n", currentDate.day, currentDate.month, currentDate.year);
        }
}

/*
 * HELP command function
 * Written by Joseph DeLong
 * parameter argc: Integer representing the number of command arguments passed in
 * parameter argv: Pointer to an array of character strings representing the specific command(s) the USER is requesting help for
 * returns 0 if all went well or another integer, depending on the appropriate error code
 */
int help(int argc, char *argv[6]) {
        int returnVal = 0;
        if(argc < 1 || strcmp(argv[0],"\0") == 0) {
                printf( "You have invoked the HELP command. For more specific help, type HELP [CMD],\n"
                                "where [CMD] is the command you would like help for.\n"
                                "\n"
                                "Command\t\t| Brief Description\n"
                                "________________|_______________________________________________________________"
                                "date\t\t| Display/Set the current system date\n"
                                "exit\t\t| Exit the system\n"
                                "ls\t\t| Display the contents of the Present Working Directory\n"
                                "version\t\t| Display the current version of the OS\n"
                                "create-pcb\t| Creates a new PCB, with a unique, user-specified name\n"
                                "delete-pcb\t| Deletes the user-specified PCB from the system\n"
                                "block\t\t| Blocks the user-specified PCB\n"
                                "unblock\t\t| Unblocks the user-specified PCB\n"
                                "suspend\t\t| Suspends the user-specified PCB\n"
                                "resume\t\t| Resumes the user-specified suspended PCB\n"
                                "set-priority\t| Sets the user-specified PCB to the user-specified priority\n"
                                "show-pcb\t| Shows the user-specified PCB & its internal guts\n"
                                "show-ready\t| Shows all PCBs currently in the READY state\n"
                                "show-blocked\t| Shows all PCBs currently in the BLOCKED state\n"
                                "show-all\t| Shows all PCBs\n"
                                "\n" );
        }
        else {
                //Secret / Extra Commands
                if(strncmp(argv[1],"carrot",6) == 0) {
                        printf( "This has something to do with getting on Appaloosa's good side. Maybe she will\n"
                                        "let you ride her?\n");
                }
                else if(strncmp(argv[1],"clear",5) == 0) {
                        printf("This command clears the screen.\n");
                }
                //R1 Commands
                else if(strncmp(argv[1],"date",4) == 0) {
                        printf( "To SHOW the current date, use date.\n"
                                        "To SET the system date, use date -s YYYY MM DD.\n"
                                        "You may enter negative years, indicating BCE.\n"
                                        "Months must be between 1 and 12.\n"
                                        "Days must not exceed their respective months.\n"
                                        "Leap year support is included.\n");
                }
                else if(strncmp(argv[1],"exit",4) == 0) {
                        printf( "This command will exit the Appaloosa OS. Make sure you have saved your work\n"
                                        "before exiting.\n");
                }
                else if(strncmp(argv[1], "help",4) == 0) {
                        printf("Yes, this is the help command.\n");
                }
                else if(strncmp(argv[1],"ls",2) == 0) {
                        printf("This command displays the contents of the Current Directory.\n");
                }
                else if(strncmp(argv[1],"version",7) == 0) {
                        printf( "This command shows the version and developer information for the current version\n"
                                        "of the Appaloosa OS.\n");
                }
                //R2 Commands
                else if(strncmp(argv[1], "create-pcb",10) == 0) {
                        printf( "This command accepts 3 arguments:.\n"
                                        "\tA character string (up to 9 characters long), indicating the NAME of the PCB\n"
                                        "\tAn integer, representing the Process Class of this PCB\n\t\t(0 = System, 1 = Application)\n"
                                        "\tAn integer, representing the Priority of this PCB (-128 to 127)\n");
                }
                else if(strncmp(argv[1], "delete-pcb",10) == 0) {
                        printf( "This command deletes the specified PCB, free-ing its associated memory.\n"
										"It must have 1 argument passed to it: the name of the PCB to be\n"
                                        "deleted.\n");
                }
                else if(strncmp(argv[1], "block",5) == 0) {
                        printf("This command places the specified PCB into the blocked queue.\n"
										"It must have 1 argument passed to it: the name of the PCB to be blocked.\n");
                }
                else if(strncmp(argv[1], "unblock",7) == 0) {
                        printf("This command places the specified PCB into the ready queue. It\n"
										"takes in 1 argument: the name of the PCB to be unblocked.\n");
                }
                else if(strncmp(argv[1], "suspend",7) == 0) {
                        printf("This command sets the suspended flag of the specified PCB to 1. It\n"
										"takes in 1 argument: the name of the PCB to be suspended.\n");
                }
                else if(strncmp(argv[1], "resume",6) == 0) {
                        printf("This command sets the suspended flag of the specified PCB to 0. It\n"
										"takes in 1 argument: the name of the PCB to be resumed.\n");
                }
                else if(strncmp(argv[1], "set-priority",12) == 0) {
                        printf( "This command takes in 2 arguments:\n"
                                        "\tA character string, representing the name of the PCB\n"
                                        "\tAn integer, representing the new Priority of the PCB\n");
                }
                else if(strncmp(argv[1], "show-pcb",8) == 0) {
                        printf("This command will display the internal information contained\n"
										"the specified PCB. It takes in 1 argument: The\n"
										"name of the PCB to be displayed.\n");
                }
                else if(strncmp(argv[1], "show-ready",10) == 0) {
                        printf( "This command displays information contained within all PCBs currently in the\n"
                                        "Ready Queue.\n");
                }
                else if(strncmp(argv[1], "show-blocked",12) == 0) {
                        printf( "This command displays information contained within all PCBs currently in the\n"
                                        "Blocked Queue.\n");
                }
                else if(strncmp(argv[1], "show-all",8) == 0) {
                        printf("This command displays information contained within all PCBs.\n");
                }
                else {
                        printf("You have requested help for a non-existent command: %s\n",argv[1]);
                        returnVal = -56712; //placeholder for error code return (if we are going to do this)
                }
        }
        return returnVal;
}

/*
 * DIRECTORY function
 * Written by Justin Hamric
 * This function prints out the name and size (in bytes) of all files found in the current directory.
 */
int ls(char *input[6], int command_args) {
        char name_buf[40]; //can return a file name of length up to 20
        int buf_size = 40;
        long file_size_p; // size of returned file in bytes
        int i;
		int paginate = 0;
        char user_input[40];
        if(command_args == 0) {
                sys_open_dir("\0");
                while(sys_get_entry(name_buf, buf_size, &file_size_p) != -113) {
						if(paginate>20){
							printf("Press enter to proceed to the next page\n");
							getch();
							paginate = 0;
						}
                        printf("%s of size %ld bytes.\n", name_buf, file_size_p);
						paginate++;
                }
                sys_close_dir();
        }else if(command_args == 1) {
                input[1][strlen(input[1])-1] = '\0';
                //printf("One Argument: %s  length: %d \n", input[1], strlen(input[1])); 
                if(sys_open_dir(input[1])>=0) {
                        while(sys_get_entry(name_buf, buf_size, &file_size_p) != -113) {
								if(paginate>20){
									printf("Press enter to proceed to the next page\n");
									getch();
									paginate = 0;
								}
                                printf("%s of size %ld bytes.\n", name_buf, file_size_p);
								paginate++;
                        }
                }else {
                        printf("The directory could not be found.\n");
                }
                sys_close_dir();
        }
        else {
                printf("Too many arguments.\n");
        }
        return 0;
}

/* EXIT function
 * Written by Alex Bouvy
 * parameter *exit: an integer pointer, which indicates whether this function ran correctly so MAIN can continue to system cleanup
 */
int r_exit(int *exit) {

        char question[19] = "Really exit? (y/n)\n";
        char input_buffer[256];
        char original_input[256];
        char* input[6];
        int qlength = 19;
        int bufferSize = 256;
        int i;
        int command_args = 0;
        sys_req(2,1, question, &qlength); //print question
        sys_req(1, 1, input_buffer, &bufferSize); //get answer to question
        strcpy(original_input,input_buffer);
        strxfrm(original_input,original_input, strlen(original_input));
        input[0] = strtok(input_buffer," ");
        for(i=1;i<6;i++){
                input[i]=strtok(NULL," ");
                if(input[i]==NULL) break;
                else command_args = i;
        }
        if(strlen(input[0])>1){
                strxfrm(input[0],input[0], strlen(input[0]));
        }
        strcat(input[0],"\0");
        //hacky fix for other tokenization issue
        if(command_args==1){
                if(!(strcmp(input[1],"\n"))){
                        command_args=0;
                        input[1] = NULL;
                }
        }
        if(command_args>0){
                printf("'%s' is not valid.\n",original_input);
        }
        else if(!(strcmp(input[0],"Y\0"))) {
                *exit = 0;
        }
        else if(!(strcmp(input[0],"y\0"))) {
                *exit = 0;
        }
        else if(!(strcmp(input[0],"N\0"))) {
                //do nothing
        }
        else if(!(strcmp(input[0],"n\0"))) {
                //do nothing
        }
        else printf("'%s' is not valid.\n",input[0]);
        return 0;
}

/*
 * VERSION function
 * Written by Joseph DeLong
 * parameters: NONE
 * returns: NOTHING
 */
void version(void) {
        printf("%s\n",VERSION_INFO);// this info is held in defines.h
}
//--------------------------------------------------------/R1 COMMANDS---------------------------------------------------------//

//---------------------------------------------------------R2 COMMANDS---------------------------------------------------------//
void R2Init(struct MPX_Q *ready, struct MPX_Q *blocked) {
        ready = sys_alloc_mem(sizeof(struct MPX_Q));
        blocked = sys_alloc_mem(sizeof(struct MPX_Q));
        (*ready).count = 0;
        (*ready).head = NULL;
        (*ready).tail = NULL;
        (*blocked).count = 0;
        (*blocked).head = NULL;
        (*blocked).tail = NULL;
}

/*
 * R2Clean Function
 *      Created on: Sep 30, 2013
 *      Written by: Joseph DeLong and Alex J. Newcomer
 *      Calls deletePCB()(which frees the pcb's) for all and then frees the queues
 *              NOTE: This should be checked with the mem function
 */
void R2Clean(struct MPX_Q *ready, struct MPX_Q *blocked) {
        int i;
                MPX_PCB *temp = (*ready).head; 
                MPX_PCB *temp1;
                //clear ready
        for(i = 0; i < (*ready).count; i++) {
                        temp1 = (*temp).next;
                        freePCB(temp);
                        temp = temp1;   
        }
                //clear blocked
                temp = (*blocked).head;
        for(i = 0; i < (*blocked).count; i++) {
                        temp1 = (*temp).next;
                        freePCB(temp);
                        temp = temp1;                           
                }
        sys_free_mem(ready);
        sys_free_mem(blocked);
}

/* Alex Bouvy
 * freePCB()
 * Uses the support function sys_free_mem to free all the memory associated with a pcb
 *      Params:
 *      Pointer to pcb to free
 * 
 *      Returns:
 *      Nothing OR error/success code
 */
int freePCB(MPX_PCB* pcb){
        return sys_free_mem(pcb);
}


/* Alex Bouvy
 * allocPCB()
 * Uses the support function sys_alloc_mem(0 to allocate memory for a PCB
 * Returns:
 *      Pointer to the PCB if successful
 *      NULL if error, including if one of the parameters is invalid
 */
MPX_PCB *allocPCB(){
        MPX_PCB* p;
        p = sys_alloc_mem(sizeof(MPX_PCB)); 
        return p;
}

/* Alex Bouvy
 * SetupPCB()
 * Procedures: Setup-PCB 19/32
 * CS 450 LAB Module R2 Feb. 1, 2013
 * Initializes the information in your PCB structure. Does not
 * insert into a queue. Calls Allocate-PCB(), sets state to
 * ready, not suspended (this will change later)
 * Parameters: Process Name, class, priority
 * Returns:
 *      Pointer to the PCB if successful
 *      NULL if error, including if one of the parameters is invalid
 */

MPX_PCB* setupPCB(char procName[9], int processClass, int prio) {
        MPX_PCB* pcb;   

        //error check
        if(strlen(procName)>8){
                printf("Invalid process name provided.\n");
        }
        else{
                //initialize PCB structure:
                pcb = allocPCB();
                strcpy((*pcb).processName,procName);
                strcat((*pcb).processName,"\0");
                (*pcb).processID = 0;   
                (*pcb).processClass = processClass;
                (*pcb).priority = prio;
                (*pcb).pcb_state = 1;
                (*pcb).isSuspended = 0;
                (*pcb).memorySize = 1024;
                (*pcb).load_address = 0;
                (*pcb).exec_address = 0;
        }
        return pcb;
}

/*
 * clear.c
 *
 *  Created on: Sep 12, 2013
 *      Author: Joseph DeLong
 */

/*
 * CLEAR SCREEN function
 * parameters: NONE
 * returns: Nothing.
 */
void clear(void) {
        sys_req(3,1,((void *)0),((void *)0)); //CLEAR(3) the TERMINAL(1)
}

/* Alex Bouvy
 * show_ready()
 */
void show_ready(struct MPX_Q* r){
        int index;
        MPX_PCB* temp;
		int paginate = 0;
		int queueCurrent = 1;
		clear();
        printf("\n");
        printf("Ready Queue:\n\n");
		paginate = paginate + 3;
        temp = (*r).head;
        for(index = 0; index<(*r).count; index++){
				if(paginate>18){
							printf("Press enter to proceed to the next page\n\n");
							getchar();
							paginate = 0;
							clear();
				}
                printf("Name: %s\n",(*temp).processName);
                printf("Class: %d\n",(*temp).processClass);
                printf("State: %d\n",(*temp).pcb_state);
                printf("Suspended: %d\n",(*temp).isSuspended);
                printf("Prio: %d\n",(*temp).priority);
				printf("\n");
				paginate = paginate +6;
                temp = (*temp).next;
        }
		printf("\n");
		sleep(1);
		printf("Press enter to proceed to the next page\n\n");
		getchar();
		clear();
		
        
}

/* Alex Bouvy
 * show_blocked()
 */
void show_blocked(struct MPX_Q* b){
        int index;
        MPX_PCB* temp;
        int paginate = 0;
		int queueCurrent = 1;
		clear();
        printf("\n");
        printf("Blocked Queue:\n\n");
		paginate = paginate + 3;
        temp = (*b).head;
        for(index = 0; index<(*b).count; index++){
			if(paginate>18){
				printf("Press enter to proceed to the next page\n\n");
				getchar();
				paginate = 0;
				clear();
			}
                printf("Name: %s\n",(*temp).processName);
                printf("Class: %d\n",(*temp).processClass);
                printf("State: %d\n",(*temp).pcb_state);
                printf("Suspended: %d\n",(*temp).isSuspended);
                printf("Prio: %d\n",(*temp).priority);
				printf("\n");
				paginate = paginate + 6;
                temp = (*temp).next;
        }
		printf("\n");
		sleep(1);
		printf("Press enter to proceed to the next page\n\n");
		getchar();
		clear();
		
        printf("\n");
}

/* Alex Bouvy
 * show_blocked()
 */

void disp(struct MPX_Q* r,struct MPX_Q* b){
        int index;
        MPX_PCB* temp;
        
        printf("\n");
	printf("Ready Queue:\n");
	temp = (*r).head;
        for(index = 0; index<(*r).count; index++){
                printf("%s %d\n",(*temp).processName,(*temp).priority);
                temp = (*temp).next;
        }
        printf("\n");
        printf("Blocked Queue:\n");
        temp = (*b).head;
        for(index = 0; index<(*b).count; index++){
                printf("%s %d\n",(*temp).processName,(*temp).priority);
                temp = (*temp).next;
        }
        printf("\n");
}


/* Alex Bouvy
 * show_all()
 */
void show_all(struct MPX_Q* r, struct MPX_Q* b){
        show_ready(r);
        show_blocked(b);
}

/* Alex Bouvy
 * insert_blocked()
 */
void insert_blocked(struct MPX_PCB* new, struct MPX_Q* b) {
        int index;
        
        if((*b).count==0){
                (*b).head = new;
                (*b).tail = new;
		(*new).next = NULL;
		(*new).prev = NULL;
                (*b).count++;
        }
        else{
                (*(*b).tail).next = new;
                (*new).prev = (*b).tail; 
                (*b).tail = new;        
                (*b).count++;
        }
}

/* Alex Bouvy
 * insert_ready()
 */
void insert_ready(struct MPX_PCB* new, struct MPX_Q* r) {
        int index;
        int prio = (*new).priority;
        MPX_PCB* temp;
        MPX_PCB* prev;
        
        if((*r).count==0){
                (*r).head = new;
                (*r).tail = new;
		(*new).next = NULL;
		(*new).prev = NULL;
                (*r).count++;
        }
        else if(prio>(*(*r).head).priority){
                (*new).next = (*r).head;
                (*(*r).head).prev = new;
                (*r).head = new;
                (*r).count++;
        }
        else{
                temp = (*r).head;
                for(index = 0; index<(*r).count; index++){
                        if((*new).priority>(*temp).priority){
                                (*prev).next = new;
                                (*new).prev = prev;
                                (*new).next = temp;
                                (*temp).prev = new;
                                (*r).count++;
                                return;
                        }
                        prev = temp;
                        temp = (*temp).next;
                }
                (*prev).next = new;
                (*r).tail = new;
                (*new).prev = prev;
                (*r).count++;
        }
}
        
/* Alex Bouvy
 * removePCB()
 */
int removePCB(struct MPX_PCB* pcbJ, struct MPX_Q* q){
        //pcbJ is head
        if(!strcmp((*(*q).head).processName,(*pcbJ).processName)){
                (*q).head = (*(*q).head).next;
                (*(*q).head).prev = NULL;
        }       
        //pcbJ is tail
        else if((*pcbJ).next == NULL){
                (*q).tail = (*pcbJ).prev;
                (*(*q).tail).next = NULL;
        }
        //pcbJ is in middle     
        else{
                (*(*pcbJ).prev).next = (*pcbJ).next;
                (*(*pcbJ).next).prev = (*pcbJ).prev;    
        }
        (*q).count--;
        return 1;
}

/*
 * FIND PCB
 * Written by Joseph DeLong and Alex J. Newcomer
 * Debugged by pimp daddy
 * Searches all queues for a process with the given name.
 * Parameters: Process Name
 * Returns:
 *      Pointer to the PCB if found
 *      NULL if error
 */
MPX_PCB* find_ready(char processName[9], struct MPX_Q *r) {
        MPX_PCB* temp;
        int found = 0, count = 0, count1 = 0;
        temp = (*r).head;
	for(count = 0; count<(*r).count; count++){
		if(!strcmp((*temp).processName,processName)) { //if names match
                        return temp;
                }
		temp = (*temp).next;
	}
	return NULL;
}

MPX_PCB* find_blocked(char processName[9], struct MPX_Q *b) {
        MPX_PCB* temp;
        int found = 0, count = 0, count1 = 0;
        temp = (*b).head;
	for(count = 0; count<(*b).count; count++){
		if(!strcmp((*temp).processName,processName)) { //if names match
                        return temp;
                }
		temp = (*temp).next;
	}
	return NULL;
}
//created by Alex J. Newcomer
void blockPCB(char processName[9], struct MPX_Q *a, struct MPX_Q *b){
MPX_PCB* temp;
processName[strlen(processName)- 1] = '\0';
temp = find_ready(processName, a);
        if(temp == NULL){
         temp = find_blocked(processName, b);
                if(temp == NULL){
                        printf("%s doesn't exist.\n", processName);
                } else {
                        printf("%s is already blocked.\n", processName);
                }
        } else {
        printf("'%s' blocked.\n",processName);
	removePCB(temp, a);
        insert_blocked(temp, b);
        }
}

//created by Alex J. Newcomer
void unblockPCB(char processName[9], struct MPX_Q *a, struct MPX_Q *b){
MPX_PCB* temp;
processName[strlen(processName)- 1] = '\0';
temp = find_ready(processName, a);
        if(temp == NULL){
         temp = find_blocked(processName, b);
                if(temp == NULL){
                        printf("%s doesn't exist.\n", processName);
                } else {
                printf("'%s' unblocked.\n",processName);
		removePCB(temp, b); 
                insert_ready(temp, a);
                }
        } else {
                printf("%s is already ready.\n", processName);  
        }
}
/*
 * LOGO function

 * Written by Joseph DeLong
 * Displays an animated ASCII logo of a running horse, as well as a final load screen, with the name of the OS
 * parameters: NONE
 * returns: an Integer representing either 0 (normal operation/termination) or a non-zero number (error code)
 * TODO: Change all printf() statements to sys_req() statements
 * TODO: Change all delay() statements to sys_req() statements?
 */
int logo(void) {
        //open all logo files
        int h,i,j,k;
        FILE *logo1 = fopen("logo01","r");
        FILE *logo2 = fopen("logo02","r");
        FILE *logo3 = fopen("logo03","r");
        FILE *logo4 = fopen("logo04","r");
        FILE *logo5 = fopen("logo05","r");
        FILE *logo6 = fopen("logo06","r");
        FILE *logo7 = fopen("logo07","r");
        FILE *logo8 = fopen("logo08","r");
        FILE *logoF = fopen("logoF","r");
        //make FILE array
        FILE *logos[8];
        logos[0] = logo1;
        logos[1] = logo2;
        logos[2] = logo3;
        logos[3] = logo4;
        logos[4] = logo5;
        logos[5] = logo6;
        logos[6] = logo7;
        logos[7] = logo8;
        //set up for iteration
        for (h = 0; h < 4; h++) { //number of animations
                //set seek position to start of files
                fseek(logo1,0,SEEK_SET);
                fseek(logo2,0,SEEK_SET);
                fseek(logo3,0,SEEK_SET);
                fseek(logo4,0,SEEK_SET);
                fseek(logo5,0,SEEK_SET);
                fseek(logo6,0,SEEK_SET);
                fseek(logo7,0,SEEK_SET);
                fseek(logo8,0,SEEK_SET);
                for(i = 0; i < 8; i++) { //number of frames
                        for(j = 0; j < 25; j++) { //number of rows in each frame
                                for(k = 0; k < 80; k++) { //number of characters in each row
                                        printf("%c", fgetc(logos[i]));
                                }
                                fgetc(logos[i]);//this should clear the newline character from being captured
                        }
                        delay(250); //wait a quarter of a second after each frame <dos.h>
                }
        }
        //display final load screen
        fseek(logoF,0,SEEK_SET);
        for(j = 0; j < 25; j++) { //number of rows
                for(k = 0; k < 80; k++) { //number of characters in each row
                        printf("%c", fgetc(logoF));
                }
                fgetc(logos[i]);//this should clear the newline character from being captured
        }
        delay(5000); //wait 5 seconds <dos.h>
        //close all logo files
        fclose(logo1);
        fclose(logo2);
        fclose(logo3);
        fclose(logo4);
        fclose(logo5);
        fclose(logo6);
        fclose(logo7);
        fclose(logo8);
        fclose(logoF);
        //exit
        return 0;
}
//--------------------------------------------------------/R2 COMMANDS---------------------------------------------------------//